﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using ALDIOrganizer.Properties;

namespace ALDIOrganizer
{

    [Serializable]
    public class ShiftStub
    {
        public TimeByQuarters Start;
        public TimeByQuarters End;
        public bool Opening;
        public bool Closing;

        public override bool Equals(object obj)
        {
            if (!(obj is ShiftStub))
            {
                return false;
            }

            var other = (ShiftStub)obj;

            if (Opening ^ other.Opening ||
                Start != other.Start)
                return false;

            if (Closing ^ other.Closing ||
                End != other.End)
                return false;

            return true;
        }

        public override string ToString()
        {
            var shift = new Shift
                            {
                                opening = this.Opening,
                                closing = this.Closing,
                                Start = this.Start,
                                Finish = this.End
                            };

            return shift.ToStringAbsolute();
        }        
    }
    

            
    
    
    

    // A Shift that has had some row assigned to it already.
    [Serializable]
    public partial class Shift : ICloneable, IComparable
    {
        [NonSerialized]
        internal bool MarkedAsOdd;
      
        
        public Weekday Day;
        public Position JobPosition;
        /* An instance of a Shift class does not live "On its own".
         * It holds a reference to a GetParent it is a part of. */
        [NonSerialized]
        public Sheet Parent;
        
        // So, who got that Shift? 
        public Int64 EmployeeID;

        public EmployeeInRota GetEmployee
        {
            get
            {
                return Parent.IsRota ?
                    (Parent as Rota).Employees.GetEmployee(EmployeeID) :
                    null;
            }
        }

        public SumOfHours Length()
        {
            var result = new SumOfHours();
            var howLong = (double)((Finish.Time - Start.Time)) / 4;
            if (howLong < 0)
            {
                howLong = 0;
            }
            
            switch (Parent.Mode)
            {
                case SheetType.Rota:
                    {
                        if (GetEmployee == null
                            || GetEmployee.ContractStatuses.Value[Day.ToInt0()] == null)
                        {
                            return new SumOfHours();
                        }
                        if (GetEmployee.ContractStatuses.Value[Day.ToInt0()].role.IsOffProd())
                        {
                            result.OffProductivity += howLong;
                        }
                        else
                        {
                            result.OnProductivity += howLong;
                        }
                        break;
                    }

                default: // SheetType.Template:
                    {
                        if (JobPosition == Position.Trainee)
                        {
                            result.OffProductivity += howLong;
                        }
                        else
                        {
                            result.OnProductivity += howLong;
                        }
                        break;
                    }                    
            }
            return result;
        }

        
        // what Time does the Shift Start and Finish
        private TimeByQuarters _start;
        private TimeByQuarters _end;
        
        public bool opening;
        public bool closing;

        internal protected Int32 GetLongHashCode
        {
            get
            {                
                var startHash = opening ?
                    128 :
                    _start.Time; // maximum = 95
                var endHash = closing ?
                    128 :
                    _end.Time; // maximum = 95
                return (startHash << 8) + endHash; // _startHash shifted left by 8 bits
            }
        }

        public WorkingHoursSpan[] GetWorkingHours
        {
            get
            {
                if (Parent is Rota)
                {
                    return ((Rota)Parent).GetWorkingHours;
                }
                if (Parent is Template)
                {
                    return ((Template)Parent).WorkingHours;
                }
                // if we got here, GetParent was neither Rota nor Template
                // Debugger.Break();

                return null;                
            }
        }
        public TimeByQuarters Start
        {
            get
            {
                /* If opening bool is set to true, we ignore the "real" Value of _start
                 * and instead, return the opening hour (retrieved from the "parenting" GetParent) */
                return opening ?
                    GetWorkingHours[(int)Day].Open :
                    _start;
            }
            set { _start = value; }
        }

        public TimeByQuarters Finish
        {
            get
            {
                /* If closing bool is set to true, we ignore the "real" Value of _end
                 * and instead, return the closing hour (retrieved from the "parenting" GetParent) */
                return this.closing ? GetWorkingHours[(int)this.Day].Close : this._end;
            }

            set { this._end = value; }
        }
        
        // Returns the "absolute" _role of the Day of the Shift in the calendar
        public DateTime When
        {
            get
            {
                if (Parent is Rota)
                    return ((Rota)Parent).Monday.AddDays(Day.ToInt0());                
                return default(DateTime).AddDays(Day.ToInt0());                
            }            
        }

        internal void SetParent(Sheet pParent)
        {
            Parent = pParent;
        }

        private string ToStringOpCl(bool openAsOp, bool closeAsCl)
        {
            string _from;
            string _to;

            if (openAsOp && opening)
            {
                _from = Resources.SHEET_CONVENTION_Shortcut_Open;
            }
            else
            {
                _from = Start.ToString();
            }

            if (closeAsCl && closing)
            {
                _to = Resources.SHEET_CONVENTION_Shortcut_Close; ;
            }
            else
            {
                _to = Finish.ToString();
            }

            var result = Resources.SHEET_CONVENTION_Shift_Format.Replace(
                "#",
                _from).Replace(
                "$",
                _to);
            return result;
        }

        public override string ToString()
        {
            return ToStringOpCl(
                Settings.Default.SHEET_DisplayOp,
                Settings.Default.SHEET_DisplayCl);
        }

        public string ToStringAbsolute()
        {
            return ToStringOpCl(true, true);
        }

        // Extracts the basic properties
        public ShiftStub ToShiftStub()
        {
            return new ShiftStub()
            {
                Opening = this.opening,
                Closing = this.closing,
                Start = this._start,
                End = this._end
            };
        }

        #region ICloneable Members

        public object Clone()
        {
            return Cloner.Copy<Shift>(this);
        }

        #endregion

        #region IComparable Members

        public int CompareTo(object obj)
        {
            Shift s1 = this;
            Shift s2 = (Shift)obj;
            return s1.Start.Time != s2.Start.Time ?
                s1.Start.CompareTo(s2.Start) :
                s1.Finish.CompareTo(s2.Finish);
        }

        #endregion
        
        public override bool Equals(object obj)
        {
            var s2 = obj as Shift;
            if (s2 == null) return false;

            if (this.opening != s2.opening) return false;
            if (this.closing != s2.closing) return false;
            if (!this.opening) if (this._start != s2._start) return false;
            if (!this.closing) if (this._end != s2._end) return false;
            if (this.When != s2.When) return false;
            if (this.Day != s2.Day) return false;
            if ((this.EmployeeID != s2.EmployeeID) && (this.JobPosition != s2.JobPosition)) return false;

            return true;
        }

        public int GetHashCode(Shift obj)
        {
            return obj.ToString().ToLower().GetHashCode();
        }
        

        public static bool IsShift(string pStringInput)
        {
            return System.Text.RegularExpressions.Regex.IsMatch(
                pStringInput,
                Settings.Default.REGEX_ValidShiftSyntax);
        }
        
    }


  
}
